from kiwi.core.base import Meta
from itertools import combinations
import random 
import numpy as np

#*****************************************************************************
# PURPOSE: 
# USAGE:   
# PASSED ARGS:  
# RETURN ARGS: 
# Error - Fail Error Message
#*****************************************************************************
class Sampler( Meta ):
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def __init__( self, name = "Sampler" , type = "Sampler", seed = None  ):
		Meta.__init__( name , type  )
		self.randnum = Random()
		if seed is not None:
			self.randnum.seed( seed )
		else:
			self.see
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************	
	def __del__( self ):
		Meta.__del__( self )
		del self.randnum	
		
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def setSeed( self, seed ):
		self.seed = seed
		self.randnum.seed( seed )

	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************		
	def getSeed( self ):
		return self.seed	

	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************		
	def shuffleIndex( self, start, end ):
		listIndex = range( start, end )
		self.randnum.shuffle( listIndex )
		return listIndex 
	
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************	
	def shuffleList( self, list ):
		listIndex = range(len(list))
		self.randnum.shuffle( listIndex )	
		return 	list[ listIndex ]
		
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def choice( self, list ):
		return self.randnum.choice( list )

	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************	
	def leaveNOut( self, n = 1, instances ):	
		indexList = range( len( instances ) )
		listLength = len( instances )	
		if n >= 1:
			comb = combinations( indexList, n )		
			for idx in comb:
				test_index = np.zeros( listLength , dtype=np.bool)
				test_index[ np.array( idx ) ] = True
				train_index = np.logical_not( test_index )
				ind = np.arange( listLength )
				train_index = ind[train_index]
				test_index = ind[test_index]
				yield train_index, test_index
			
	
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************		
	def sample( self, list ):
		pass
		
#*****************************************************************************
# PURPOSE: 
# USAGE:   
# PASSED ARGS:  
# RETURN ARGS: 
# Error - Fail Error Message
#*****************************************************************************		
class LevelNOut( Sampler ):
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def __init__( self, name = "LevelNOut" , type = "LevelNOut", seed = None  ):
		Sampler.__init__( name , type, seed  )
	
	
	
#*****************************************************************************
# PURPOSE: 
# USAGE:   
# PASSED ARGS:  
# RETURN ARGS: 
# Error - Fail Error Message
#*****************************************************************************	
class NFold( Sampler ):
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def __init__( self, name = "NFold" , type = "NFold", seed = None ):
		Sampler.__init__( name , type, seed  )
		
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************	
	def __del__( self ):
		Sampler.__del__( self )

	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def setFolds( self, numFolds ):
		self.numFolds = numFolds

	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************		
	def getFolds( self ):
		return self.numFolds
		
	
#*****************************************************************************
# PURPOSE: 
# USAGE:   
# PASSED ARGS:  
# RETURN ARGS: 
# Error - Fail Error Message
#*****************************************************************************
class StratifiedNFold( NFold ):
	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************
	def __init__( self, name = "NFold" , type = "NFold"  ):
		Sampler.__init__( name , type  )

	#*****************************************************************************
	# PURPOSE: 
	# USAGE:   
	# PASSED ARGS:  
	# RETURN ARGS: 
	# Error - Fail Error Message
	#*****************************************************************************	
	def __del__( self ):
		Sampler.__del__( self )

	
	
#*****************************************************************************
# PURPOSE: 
# USAGE:   
# PASSED ARGS:  
# RETURN ARGS: 
# Error - Fail Error Message
#*****************************************************************************
class Evaluator( Model ): 



#*****************************************************************************
# PURPOSE: 
# USAGE:   
# PASSED ARGS:  
# RETURN ARGS: 
# Error - Fail Error Message
#*****************************************************************************
class 
